<template>
	<view>
		<view class='qrcode-box'>
			<view class='qrcode-canvas-view'>
				<canvas class='qrcode-canvas' id="qrCode" canvas-id='qrcode'></canvas>
				<block v-if='logoImg'>
					<image class='logo-img opt-btn' :src='logoImg' @click='updateLogo'></image>
				</block>
				<block v-else>
					<view class='logo-img opt-btn' @click='updateLogo'>LOGO</view>
				</block>
				<view class="qrcode-color opt-btn" :style="'background:' + color" @click="toggleColorPicker">颜色</view>
			</view>
			<view class='qrcode-set'>
				<textarea class='message-content' @input="bindInput" name="message" maxlength="100" placeholder="请输入二维码内容,最多输入100个字符"></textarea>
			</view>
			<view class='qrcode-opretion'>
				<button @click='savePic' class='qrcode-btn'>生成二维码</button>
			</view>
		</view>

		<!-- 颜色选择器 -->
		<view v-show="colorPickerVisible" class="t-wrapper" @touchmove.stop.prevent="moveHandle">
			<view class="t-mask" :class="{ active: active }" @click.stop="closeColorPicker"></view>
			<view class="t-box" :class="{ active: active }">
				<view class="t-header">
					<view class="t-header-button" @click="closeColorPicker">取消</view>
					<view class="t-header-button confrim" @click="confirmColor">确认</view>
				</view>
				<view class="t-color__box" :style="{ background: `rgb(${bgcolor.r}, ${bgcolor.g}, ${bgcolor.b})` }">
					<view class="t-background boxs" @touchstart="touchstart($event, 0)" @touchmove="touchmove($event, 0)" @touchend="touchend($event, 0)">
						<view class="t-color-mask"></view>
						<view class="t-pointer" :style="{ top: site[0].top - 8 + 'px', left: site[0].left - 8 + 'px' }"></view>
					</view>
				</view>
				<view class="t-control__box">
					<view class="t-control__color">
						<view class="t-control__color-content" :style="{ background: `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})` }"></view>
					</view>
					<view class="t-control-box__item">
						<view class="t-controller boxs" @touchstart="touchstart($event, 1)" @touchmove="touchmove($event, 1)" @touchend="touchend($event, 1)">
							<view class="t-hue">
								<view class="t-circle" :style="{ left: site[1].left - 12 + 'px' }"></view>
							</view>
						</view>
						<view class="t-controller boxs" @touchstart="touchstart($event, 2)" @touchmove="touchmove($event, 2)" @touchend="touchend($event, 2)">
							<view class="t-transparency">
								<view class="t-circle" :style="{ left: site[2].left - 12 + 'px' }"></view>
							</view>
						</view>
					</view>
				</view>
				<view class="t-result__box">
					<view v-if="mode" class="t-result__item">
						<view class="t-result__box-input">{{ hex }}</view>
						<view class="t-result__box-text">HEX</view>
					</view>
					<template v-else>
						<view class="t-result__item">
							<view class="t-result__box-input">{{ rgba.r }}</view>
							<view class="t-result__box-text">R</view>
						</view>
						<view class="t-result__item">
							<view class="t-result__box-input">{{ rgba.g }}</view>
							<view class="t-result__box-text">G</view>
						</view>
						<view class="t-result__item">
							<view class="t-result__box-input">{{ rgba.b }}</view>
							<view class="t-result__box-text">B</view>
						</view>
						<view class="t-result__item">
							<view class="t-result__box-input">{{ rgba.a }}</view>
							<view class="t-result__box-text">A</view>
						</view>
					</template>

					<view class="t-result__item t-select" @click="toggleMode">
						<view class="t-result__box-input">
							<view>切换</view>
							<view>模式</view>
						</view>
					</view>
				</view>
				<view class="t-alternative">
					<view class="t-alternative__item" v-for="(item, index) in colorList" :key="index">
						<view class="t-alternative__item-content" :style="{ background: `rgba(${item.r}, ${item.g}, ${item.b}, ${item.a})` }" @click="selectColor(item)">
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import QRCode from "/utils/qrcode.js"
// 二维码相关逻辑
const qrText = ref('')
const logoImg = ref('')
const color = ref('#000000')
const QR = ref(null)
const canvasWidth = ref(0)
const canvasHeight = ref(0)

onMounted(() => {
	const res = uni.getSystemInfoSync()
	canvasWidth.value = res.windowWidth * 350 / 750
	canvasHeight.value = res.windowWidth * 350 / 750
	const qrcode = new QRCode('qrcode', {
		text: '没有填写内容哦',
		width: canvasWidth.value,
		height: canvasHeight.value,
		colorDark: '#ccc',
		colorLight: '#fff',
		correctLevel: QRCode.correctLevel.H,
		logo: '',
		successTips: false
	})
	QR.value = qrcode
})

function bindInput(e) {
	qrText.value = e.detail.value
}

function doCreateQRCode() {
	uni.showLoading({
		title: '正在生成...'
	})
	QR.value.clear()
	QR.value._opts.colorDark = color.value
	QR.value._opts.logo = logoImg.value || false
	QR.value._opts.successTips = false
	QR.value.makeCode(qrText.value)
	uni.hideLoading()
}

function isEmojiCharacter(str) {
	if (str) {
		for (let i = 0; i < str.length; i++) {
			const hs = str.charCodeAt(i)
			if (0xd800 <= hs && hs <= 0xdbff) {
				if (str.length > 1) {
					const ls = str.charCodeAt(i + 1)
					const uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000
					if (0x1d000 <= uc && uc <= 0x1f77f) {
						return true
					}
				}
			} else if (str.length > 1) {
				const ls = str.charCodeAt(i + 1)
				if (ls == 0x20e3) return true
			} else {
				if (0x2100 <= hs && hs <= 0x27ff) {
					return true
				} else if (0x2B05 <= hs && hs <= 0x2b07) {
					return true
				} else if (0x2934 <= hs && hs <= 0x2935) {
					return true
				} else if (0x3297 <= hs && hs <= 0x3299) {
					return true
				} else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
					return true
				}
			}
		}
	}
	return false
}

async function savePic() {
	if (!qrText.value) {
		uni.showToast({
			title: '二维码内容不能为空哦！',
			icon: 'none',
			duration: 2000
		})
		return
	}
	if (isEmojiCharacter(qrText.value)) {
		uni.showToast({
			title: '二维码内容目前不支持表情哦！',
			icon: 'none',
			duration: 2000
		})
		return
	}
	await doCreateQRCode()
	
	uni.canvasToTempFilePath({
		x: 0,
		y: 0,
		width: canvasWidth.value,
		height: canvasHeight.value,
		destWidth: 472,
		destHeight: 472,
		canvasId: 'qrcode',
		success(res) {
			uni.saveImageToPhotosAlbum({
				filePath: res.tempFilePath,
				success() {
					uni.showToast({
						title: '保存成功~',
						icon: 'none',
						duration: 2000
					})
				},
				fail() {
					uni.showToast({
						title: '暂无相册权限，请授权后再试',
						icon: 'none',
						duration: 2000
					})
				}
			})
		}
	})
}

function updateLogo() {
	uni.chooseImage({
		count: 1,
		sizeType: ['original', 'compressed'],
		sourceType: ['album', 'camera'],
		success(res) {
			logoImg.value = res.tempFilePaths[0]
			doCreateQRCode()
		}
	})
}

// 颜色选择器相关逻辑
const colorPickerVisible = ref(false)
const active = ref(false)
const rgba = ref({
	r: 0,
	g: 0,
	b: 0,
	a: 1
})
const hsb = ref({
	h: 0,
	s: 0,
	b: 0
})
const site = ref([
	{
		top: 0,
		left: 0
	},
	{
		left: 0
	},
	{
		left: 0
	}
])
const index = ref(0)
const bgcolor = ref({
	r: 255,
	g: 0,
	b: 0,
	a: 1
})
const hex = ref('#000000')
const mode = ref(true)
const colorList = ref([
	{ r: 244, g: 67, b: 54, a: 1 },
	{ r: 233, g: 30, b: 99, a: 1 },
	{ r: 156, g: 39, b: 176, a: 1 },
	{ r: 103, g: 58, b: 183, a: 1 },
	{ r: 63, g: 81, b: 181, a: 1 },
	{ r: 33, g: 150, b: 243, a: 1 },
	{ r: 3, g: 169, b: 244, a: 1 },
	{ r: 0, g: 188, b: 212, a: 1 },
	{ r: 0, g: 150, b: 136, a: 1 },
	{ r: 76, g: 175, b: 80, a: 1 },
	{ r: 139, g: 195, b: 74, a: 1 },
	{ r: 205, g: 220, b: 57, a: 1 },
	{ r: 255, g: 235, b: 59, a: 1 },
	{ r: 255, g: 193, b: 7, a: 1 },
	{ r: 255, g: 152, b: 0, a: 1 },
	{ r: 255, g: 87, b: 34, a: 1 },
	{ r: 121, g: 85, b: 72, a: 1 },
	{ r: 158, g: 158, b: 158, a: 1 },
	{ r: 0, g: 0, b: 0, a: 0.5 },
	{ r: 0, g: 0, b: 0, a: 0 }
])
const position = ref([])

function moveHandle() {}

function toggleColorPicker() {
	colorPickerVisible.value = !colorPickerVisible.value
	if (colorPickerVisible.value) {
		active.value = true
		setTimeout(() => {
			getSelectorQuery()
		}, 350)
	} else {
		active.value = false
	}
}

function closeColorPicker() {
	active.value = false
	setTimeout(() => {
		colorPickerVisible.value = false
	}, 500)
}

function confirmColor() {
	closeColorPicker()
	color.value = hex.value
	doCreateQRCode()
}

function toggleMode() {
	mode.value = !mode.value
}

function selectColor(item) {
	const { r, g, b, a } = item
	const rgb = {
		r: r ? parseInt(r) : 0,
		g: g ? parseInt(g) : 0,
		b: b ? parseInt(b) : 0,
		a: a ? a : 0
	}
	rgba.value = rgb
	hsb.value = rgbToHsb(rgb)
	changeViewByHsb()
}

function touchstart(e, idx) {
	const { pageX, pageY } = e.touches[0]
	index.value = idx
	setPosition(pageX, pageY, idx)
}

function touchmove(e, idx) {
	const { pageX, pageY } = e.touches[0]
	setPosition(pageX, pageY, idx)
}

function touchend(e, idx) {}

function setPosition(x, y, idx) {
	const { top, left, width, height } = position.value[idx]
	site.value[idx].left = Math.max(0, Math.min(parseInt(x - left), width))
	if (idx === 0) {
		site.value[idx].top = Math.max(0, Math.min(parseInt(y - top), height))
		hsb.value.s = parseInt((100 * site.value[idx].left) / width)
		hsb.value.b = parseInt(100 - (100 * site.value[idx].top) / height)
		setColor()
		setValue(rgba.value)
	} else {
		setControl(idx, site.value[idx].left)
	}
}

function setColor() {
	const rgb = HSBToRGB(hsb.value)
	rgba.value.r = rgb.r
	rgba.value.g = rgb.g
	rgba.value.b = rgb.b
}

function setValue(rgb) {
	hex.value = '#' + rgbToHex(rgb)
}

function rgbToHex(rgb) {
	let hex = [rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16)]
	hex = hex.map(str => (str.length === 1 ? '0' + str : str))
	return hex.join('')
}

function setControl(idx, left) {
	if (idx === 1) {
		hsb.value.h = parseInt((left / position.value[idx].width) * 360)
		changeViewByHsb()
	} else if (idx === 2) {
		rgba.value.a = left / position.value[idx].width
		setValue(rgba.value)
	}
}

function HSBToRGB(hsb) {
	let rgb = {}
	let h = Math.round(hsb.h)
	let s = Math.round((hsb.s * 255) / 100)
	let v = Math.round((hsb.b * 255) / 100)
	if (s === 0) {
		rgb.r = rgb.g = rgb.b = v
	} else {
		let t1 = v
		let t2 = ((255 - s) * v) / 255
		let t3 = ((t1 - t2) * (h % 60)) / 60
		if (h === 360) h = 0
		if (h < 60) {
			rgb.r = t1
			rgb.b = t2
			rgb.g = t2 + t3
		} else if (h < 120) {
			rgb.g = t1
			rgb.b = t2
			rgb.r = t1 - t3
		} else if (h < 180) {
			rgb.g = t1
			rgb.r = t2
			rgb.b = t2 + t3
		} else if (h < 240) {
			rgb.b = t1
			rgb.r = t2
			rgb.g = t1 - t3
		} else if (h < 300) {
			rgb.b = t1
			rgb.g = t2
			rgb.r = t2 + t3
		} else if (h < 360) {
			rgb.r = t1
			rgb.g = t2
			rgb.b = t1 - t3
		} else {
			rgb.r = 0
			rgb.g = 0
			rgb.b = 0
		}
	}
	return {
		r: Math.round(rgb.r),
		g: Math.round(rgb.g),
		b: Math.round(rgb.b)
	}
}

function rgbToHsb(rgb) {
	let hsb = { h: 0, s: 0, b: 0 }
	let min = Math.min(rgb.r, rgb.g, rgb.b)
	let max = Math.max(rgb.r, rgb.g, rgb.b)
	let delta = max - min
	hsb.b = max
	hsb.s = max !== 0 ? (255 * delta) / max : 0
	if (hsb.s !== 0) {
		if (rgb.r === max) hsb.h = (rgb.g - rgb.b) / delta
		else if (rgb.g === max) hsb.h = 2 + (rgb.b - rgb.r) / delta
		else hsb.h = 4 + (rgb.r - rgb.g) / delta
	}
	hsb.h *= 60
	if (hsb.h < 0) hsb.h = 0
	hsb.s *= 100 / 255
	hsb.b *= 100 / 255
	return hsb
}

function getSelectorQuery() {
	const views = uni.createSelectorQuery().in(this)
	views
		.selectAll('.boxs')
		.boundingClientRect(data => {
			if (!data || data.length === 0) {
				setTimeout(getSelectorQuery, 20)
				return
			}
			position.value = data
			setColorByHue(hsb.value.h)
			setValue(rgba.value)
			bgcolor.value = HSBToRGB({
				h: hsb.value.h,
				s: 100,
				b: 100
			})
			site.value[1].left = (hsb.value.h / 360) * data[1].width
			site.value[2].left = rgba.value.a * data[2].width
		})
		.exec()
}

function setColorByHue(h) {
	hsb.value.h = h
	const rgb = HSBToRGB(hsb.value)
	rgba.value.r = rgb.r
	rgba.value.g = rgb.g
	rgba.value.b = rgb.b
}
</script>

<style lang="scss" scoped>
.qrcode-box {
	font-size: 28rpx;
	width: auto;
	height: 360rpx;
	margin: 20rpx auto;
	padding: 0 40rpx;
	box-sizing: border-box;
}
.qrcode-canvas-view {
	height: 356rpx;
	width: 356rpx;
	margin: 40rpx auto;
	border: solid 1rpx #ccc;
}
.qrcode-canvas {
	margin: 2rpx;
	height: 350rpx;
	width: 350rpx;
}
.opt-btn {
	width: 80rpx;
	height: 80rpx;
	line-height: 80rpx;
	color: #fff;
	background: #000;
	box-shadow: 0 0 10rpx #999;
	font-size: 24rpx;
	text-align: center;
	border-radius: 50%;
	margin-right: 10rpx;
	position: absolute;
	right: 20rpx;
	top: 20rpx;
	z-index: 2;
}
.qrcode-color {
	top: 120rpx;
}
.logo-img {
	background: #D8B765;
}
.message-content {
	padding: 2%;
	border: 1rpx solid #ddd;
	border-radius: 8rpx;
	min-height: 40rpx;
	margin: 0;
	width: 100%;
	box-sizing: border-box;
}
.qrcode-opretion {
	width: 100%;
	overflow: hidden;
	margin-top: 30rpx;
	.qrcode-btn {
		background-image: linear-gradient(100deg, #D8B765, #B58862);
		color: #fff;
		margin: 20rpx auto;
		border-radius: 70rpx;
	}
}

.t-wrapper {
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	width: 100%;
	box-sizing: border-box;
	z-index: 9999;
}

.t-box {
	width: 100%;
	position: absolute;
	bottom: 0;
	padding: 30upx 0;
	padding-top: 0;
	background: #fff;
	transition: all 0.3s;
	transform: translateY(100%);

	&.active {
		transform: translateY(0%);
	}
}

.t-header {
	display: flex;
	justify-content: space-between;
	width: 100%;
	height: 100upx;
	border-bottom: 1px #eee solid;
	box-shadow: 1px 0 2px rgba(0, 0, 0, 0.1);
	background: #fff;
}

.t-header-button {
	display: flex;
	align-items: center;
	width: 150upx;
	height: 100upx;
	font-size: 30upx;
	color: #666;
	padding-left: 20upx;

	&:last-child {
		justify-content: flex-end;
		padding-right: 20upx;
	}

	&.confrim {
		color: #007AFF;
	}
}

.t-mask {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background: rgba(0, 0, 0, 0.6);
	z-index: -1;
	transition: all 0.3s;
	opacity: 0;

	&.active {
		opacity: 1;
	}
}

.t-color__box {
	position: relative;
	height: 400upx;
	background: rgb(255, 0, 0);
	overflow: hidden;
	box-sizing: border-box;
	margin: 0 20upx;
	margin-top: 20upx;
	box-sizing: border-box;
}

.t-background {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
}

.t-color-mask {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	width: 100%;
	height: 400upx;
	background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
}

.t-pointer {
	position: absolute;
	bottom: -8px;
	left: -8px;
	z-index: 2;
	width: 15px;
	height: 15px;
	border: 1px #fff solid;
	border-radius: 50%;
}

.t-show-color {
	width: 100upx;
	height: 50upx;
}

.t-control__box {
	margin-top: 50upx;
	width: 100%;
	display: flex;
	padding-left: 20upx;
	box-sizing: border-box;
}

.t-control__color {
	flex-shrink: 0;
	width: 100upx;
	height: 100upx;
	border-radius: 50%;
	background-color: #fff;
	background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
		linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
	background-size: 36upx 36upx;
	background-position: 0 0, 18upx 18upx;
	border: 1px #eee solid;
	overflow: hidden;
}

.t-control__color-content {
	width: 100%;
	height: 100%;
}

.t-control-box__item {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	width: 100%;
	padding: 0 30upx;
}

.t-controller {
	position: relative;
	width: 100%;
	height: 16px;
	background-color: #fff;
	background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
		linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
	background-size: 32upx 32upx;
	background-position: 0 0, 16upx 16upx;
}

.t-hue {
	width: 100%;
	height: 100%;
	background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
}

.t-transparency {
	width: 100%;
	height: 100%;
	background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(0, 0, 0));
}

.t-circle {
	position: absolute;
	top: -2px;
	width: 20px;
	height: 20px;
	box-sizing: border-box;
	border-radius: 50%;
	background: #fff;
	box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
}

.t-result__box {
	margin-top: 20upx;
	padding: 10upx;
	width: 100%;
	display: flex;
	box-sizing: border-box;
}

.t-result__item {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 10upx;
	width: 100%;
	box-sizing: border-box;
}

.t-result__box-input {
	padding: 10upx 0;
	width: 100%;
	font-size: 28upx;
	box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1);
	color: #999;
	text-align: center;
	background: #fff;
}

.t-result__box-text {
	margin-top: 10upx;
	font-size: 28upx;
	line-height: 2;
}

.t-select {
	flex-shrink: 0;
	width: 150upx;
	padding: 0 30upx;
	.t-result__box-input {
		border-radius: 10upx;
		border: none;
		color: #999;
		box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.1);
		background: #fff;
		&:active {
			box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.1);
		}
	}
}

.t-alternative {
	display: flex;
	flex-wrap: wrap;
	width: 100%;
	padding-right: 10upx;
	box-sizing: border-box;
}

.t-alternative__item {
	margin-left: 12upx;
	margin-top: 10upx;
	width: 50upx;
	height: 50upx;
	border-radius: 10upx;
	background-color: #fff;
	background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
		linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
	background-size: 36upx 36upx;
	background-position: 0 0, 18upx 18upx;
	border: 1px #eee solid;
	overflow: hidden;
	&:active {
		transition: all 0.3s;
		transform: scale(1.1);
	}
}

.t-alternative__item-content {
	width: 50upx;
	height: 50upx;
}
</style>